
import serial
import serial.tools.list_ports
import time
from threading import Thread
from draw import start_draw
def searchcom():#查找可用串口，返回可用串口名列表
    comlist = list(serial.tools.list_ports.comports())
    if len(comlist)==0:
        print("NO COM FIND")
        return 0
    else:
        comlist =[x[0] for x in comlist]
        print("Find %d."%(len(comlist)))
        #print(comlist)
        return comlist

def buildcom(portcom,baudrate=6,bytesize=3,stopbit=0,parity=0):#打开串口，成功则返回串口对象，失败返回None
    bdrate=(300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200)
    bysize=(serial.FIVEBITS, serial.SIXBITS, serial.SEVENBITS, serial.EIGHTBITS)
    stpbit=(serial.STOPBITS_ONE, serial.STOPBITS_ONE_POINT_FIVE, serial.STOPBITS_TWO)
    pity=(serial.PARITY_NONE, serial.PARITY_EVEN, serial.PARITY_ODD,serial.PARITY_MARK, serial.PARITY_SPACE)
    try:
        com = serial.Serial(portcom,baudrate=bdrate[baudrate],bytesize=bysize[bytesize],stopbits=stpbit[stopbit],parity=pity[parity],timeout=2)
        if com.is_open:
            print("-------------------------打开串口----------------------------------")
            print("打开串口：%s————波特率：%d————校验位：%s————数据位：%d————停止位：%d"%(com.name,com.baudrate,com.parity,com.bytesize,com.stopbits))
            print("-------------------------------------------------------------------")
            return com
        else:
            print("打开串口失败")
            return None
    except Exception as er:
        print("打开串口失败:",er)
        return None

def comreceive(com:serial.Serial,model="text"):#数据接收函数。com为串口对象，model为显示模式（“text” or “hex”），longth为接收数据的长度.返回接收的数据和数据长度
    if com is not None:
        if com.is_open:
            if com.in_waiting:
                time.sleep(0.1)
                longth = com.in_waiting
                text=com.read(com.in_waiting)
                if model=="hex":
                    return text.hex(),longth
                elif model=="text":
                    return text.decode("utf-8"),longth
            else:
                return None,0
        else:
            print("串口已关闭")
            return None,0
    else:
        return None,0

def comwrite(com:serial.Serial,data,model="text"):#数据发送函数，com为串口对象，model为发送模式（text or hex），data为发送的数据（str），返回发送的长度
    if com is not None and data!=0 and data.isalnum():
        if com.is_open:
            if model=="text":
                longth=com.write(data.encode("utf-8"))
                return longth
            elif model=="hex":
                pass
        else:
            print("串口已关闭")
            return None
    else:
        print("出现错误")
        return None
                
def closecom(com:serial.Serial):#关闭串口
    if com is not None and not com.is_open:
        com.close()
        return 1
    else:
        return 0
def finput(text,default):#输入函数，当输入为空或不是“hex”“q”和数字时，返回默认default
    s=input(text)
    if s=="":
        s=default
    elif s.isdigit():
        s=int(s)
    elif s=="hex" or s=="q" or s=="g":
        pass
    else:s=default
    return s


if __name__ == '__main__':
    
    while True:#一级菜单，选择串口
        comlist=searchcom()
        if comlist==0:
            input("未找到串口")#阻断，防止刷屏
            continue
        print("可用串口列表:")
        for i in range(len(comlist)):
            print("%d-----%s"%(i,comlist[i]))
        choice=input("选择串口(输入q退出):")
        if choice=="q":
            break
        elif choice.isdigit():
            choice=int(choice)
            if 0<=choice<len(comlist):#判断是否输入正确的值
                    print("配置串口:")
                    print("选择波特率:\n","0------300\n1------600\n2------1200\n3------1800\n4------2400\n5------4800\n6------9600\n7------19200\n8------38400\n9------57600\n10------115200")
                    bd=finput("选择你的波特率(默认9600):",6)
                    print("选择数据位:\n","0------5\n1------6\n2------7\n3------8")
                    bs=finput("选择你的数据位(默认8):",3)
                    print("选择停止位:\n","0------1\n1------1.5\n2------2")
                    st=finput("选择你的停止位(默认0):",0)
                    print("选择校验位:\n","0------无校验\n1-----EVEN\n2------ODD\n3------MARK\n4------SPACE")
                    pa=finput("选择你的校验位(默认无):",0)
                    com=buildcom(comlist[choice],bd,bs,st,pa)
                    if com==None or not com.is_open:
                        print("打开串口失败")
                        continue
                    else:
                        while True:#二级菜单，选择接收发送模式
                            print("选择功能：\n","0------发送模式\n1------接收模式")
                            ft=finput("选择你的模式(默认接收模式,q退出):",1)
                            if ft ==0:
                                    while True:#三级界面，发送0模式
                                        data=input("输入你想发送的数据(无输入退出):")
                                        if data=="":
                                            break
                                        else:
                                            longth=comwrite(com,data)
                                            print("发送了%d字节."%(longth))
                            elif ft==1:#三级界面，接收模式
                                    s_tick=time.time()
                                    while True:
                                        re_mode=finput("输入接收模式(text or hex，默认text,q退出,g图表模式)","text")
                                        if re_mode=="q":
                                            break
                                        elif re_mode=="g":
                                            start_draw(com)
                                            continue
                                        data,longth=comreceive(com,re_mode)
                                        n_tick=time.time()-s_tick
                                        if longth==0:
                                            print("未接收到数据")
                                            continue
                                        else:
                                            if re_mode=="text":
                                                print("-->[%f]接收到%d字节数据:%s"%(n_tick,longth,data))
                                                continue
                                            else:
                                                print("-->[%f]接收到%d字节数据:%s"%(n_tick,longth,data))
                                                continue
                            elif ft=="q":
                                break
                            else:continue
                        status=closecom(com)
                        if status==1:
                            print("串口关闭失败")
                        else:
                            print("串口关闭失败")
                        continue
            else:
                continue
        else:
            continue
    input("程序结束，输入任意键退出")

          

